package band.wukong.practice.java.core.topic.concurrency.threadpool;

import java.util.Random;
import java.util.concurrent.*;

/**
 * FutureTask（Future）有两种构造方法：使用Runnable 或者 使用Callable
 * Refer: http://blog.csdn.net/ghsau/article/details/7451464
 *
 * @author wukong(wukonggg@139.com)
 */
public class FutureWithinCallableSample {

    public static void main(String[] args) {
//        one();
//        first();
//        second();
        third();
    }

    private static void one() {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("inside callable");
                Thread.sleep(3000);
                return 666;
            }
        });

        Thread newThread = new Thread(futureTask);
        newThread.start();
        try {
            System.out.println("blocking here");
            Integer result = futureTask.get();
            System.out.println(result);
        } catch (InterruptedException | ExecutionException ignored) {
        }
    }

    /**
     * Runable way
     */
    private static void first() {
        // 1. ready
        FutureTask<Integer> future = new FutureTask<>(() -> new Random().nextInt(100));

        // 2. go
        new Thread(future).start();

        try {
            // 3. do sth. else....
            Thread.sleep(5000);// 可能做一些事情

            // 4. get the result
            System.out.println(future.get());

        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * ExecutorService way
     */
    private static void second() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        Future<Integer> future = threadPool.submit(() -> new Random().nextInt(100));
        try {
            Thread.sleep(5000);// 可能做一些事情
            System.out.println(future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        threadPool.shutdown();
    }

    /**
     * 执行多个带返回值的任务，并取得多个返回值。
     * 细节说明：
     * 1. 其实也可以不使用CompletionService。
     *    可以先创建一个装Future类型的集合，用Executor提交的任务返回值添加到集合中，最后遍历集合取出数据
     * 2. 提交到CompletionService中的Future是按照完成的顺序排列的，这种做法中Future是按照添加的顺序排列的
     */
    private static void third() {
        ExecutorService threadPool = Executors.newCachedThreadPool();
        CompletionService<Integer> cs = new ExecutorCompletionService<>(threadPool);
        for(int i = 1; i < 5; i++) {
            final int taskID = i;
            cs.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    return taskID;
                }
            });
        }

        // 可能做一些事情

        for(int i = 1; i < 5; i++) {
            try {
                System.out.println(cs.take().get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        threadPool.shutdown();
    }
}
